package com.zbxj.wyz.service;


import com.zbxj.wyz.domain.SystemUser;
import com.zbxj.wyz.mapper.UserMapper;
import com.zbxj.wyz.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.util.Objects;

/*
Authentication接口: 它的实现类封装了当前访问的用户的相关信息。
AuthenticationManager接口：定义了认证Authentication的方法
UserDetailsService接口（自定义的实现类为UserDetailsServiceImpl）：接口中的loadUserByUsername()用来根据用户名查询用户的详细信息。
UserDetails接口：封装了用户的详细信息。通过UserDetailsService接口中的loadUserByUsername()方法将数据库查询到的用户名、密码、权限封装成UserDetails对象返回，然后将这些信息封装到Authentication对象中。
*/
@Service
public class LoginService {
    @Autowired
    UserService userService;
    @Autowired
    UserMapper userMapper;
    @Autowired
    private AuthenticationManager authenticationManager;//在WebSecurityConfigurerAdapter的子类SecurityConfig类（SecurityConfig是自定义的类）中，通过重载authenticationManagerBean()方法并在方法上方加上@Bean让框架的AuthenticationManager对象可以被外部程序使用
    @Autowired
    private RedisTemplate redisTemplate;
    public ResponseEntity<String> login(SystemUser user) {
        //调用AuthenticationManager对象的authenticate方法进行用户认证
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getName(),user.getPwd());

        Authentication authenticate = authenticationManager.authenticate(authenticationToken);//默认调用UserDetailsServiceImpl类中的loadUserByUsername获取用户信息并进行认证，把用户信息封装在authenticate对象中

        if(Objects.isNull(authenticate)){
            throw new RuntimeException("用户名或密码错误");
        }

        //在本例中使用SystemUser.name生成token
        UserDetails loginUser = (UserDetails) authenticate.getPrincipal();//获取authenticate对象中的UserDetails对象
        String username=loginUser.getUsername();
        String jwt = JwtUtil.createJWT(username);//利用username生成token
        //authenticate存入redis
        redisTemplate.opsForValue().set("login_"+username,loginUser);
        //把token响应给前端
        MultiValueMap<String,String> header=new LinkedMultiValueMap<>();
        header.add("token",jwt);
        return new ResponseEntity("登陆成功",header, HttpStatus.OK);
    }
    public ResponseEntity logout() {
        //在自定义的过滤器JwtAuthenticationTokenFilter中，只要输入的token合法，就通过SecurityContextHolder.getContext().setAuthentication(authenticationToken)语句将对应的用户信息写入就通过SecurityContextHolder中
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();//获取SecurityContextHolder中存放的用户信息
        String username = (String) authentication.getPrincipal();//获取authenticate对象中的UserDetails对象
        redisTemplate.delete("login_"+username);
        return new ResponseEntity("退出成功",HttpStatus.OK);
    }

    public int adduser(SystemUser user){return userMapper.addUser(user);}
    public SystemUser getnameUser(String name){
        return userMapper.getnameUser(name);
    }
}
